// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package types2

import "sync/atomic"

// 注意：这是一个uint32而不是uint64，因为
// 各自的64位原子指令在所有平台上都不可用。
var lastID uint32

// nextID返回一个单调递增1的值，每个调用从1开始。可以同时召开。
func nextID() uint64 { return uint64(atomic.AddUint32(&lastID, 1)) }

// TypeParam表示类型参数类型。
type TypeParam struct {
	check *Checker  // 用于惰性类型绑定完成
	id    uint64    // 唯一id，仅用于调试
	obj   *TypeName // 对应的类型名称
	index int       // 按源顺序的类型参数索引，从0开始
	bound Type      // 任何类型，但其基础最终是用于正确程序的*接口（参见TypeParam.iface）
}

// Obj返回类型参数t的类型名。
func (t *TypeParam) Obj() *TypeName { return t.obj }

// NewTypeParam返回一个新的TypeParam。类型参数可以通过调用SetTypeParams在命名的
// 或签名类型上设置。在多个
// 类型上设置类型参数将导致死机。
// 
// 约束参数可以为零，稍后通过SetConstraint进行设置。如果
// 约束为非零，则必须对其进行完全定义。
func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
	return (*Checker)(nil).newTypeParam(obj, constraint)
}

// 检查可能为零
func (check *Checker) newTypeParam(obj *TypeName, constraint Type) *TypeParam {
	// 始终递增lastID，即使未使用它。
	id := nextID()
	if check != nil {
		check.nextID++
		id = check.nextID
	}
	typ := &TypeParam{check: check, id: id, obj: obj, index: -1, bound: constraint}
	if obj.typ == nil {
		obj.typ = typ
	}
	// iface可能会突变typ。绑定，因此我们必须确保在结果TypeParam转义之前至少调用一次iface（）。
	if check != nil {
		check.needsCleanup(typ)
	} else if constraint != nil {
		typ.iface()
	}
	return typ
}

// Index返回其参数列表中类型param的索引，如果
// 类型参数尚未绑定到类型，则返回-1。
func (t *TypeParam) Index() int {
	return t.index
}

// Constraint返回为t指定的类型约束。
func (t *TypeParam) Constraint() Type {
	return t.bound
}

// SetConstraint为t设置类型约束。
// 
// 必须在绑定的基础
// 完全定义后，由NewTypeParam的用户调用，然后才能以任何方式使用类型参数，而不是
// 形成其他类型。一旦SetConstraint返回接收器，t就可以安全地同时使用
// 了。
func (t *TypeParam) SetConstraint(bound Type) {
	if bound == nil {
		panic("nil constraint")
	}
	t.bound = bound
	// iface可能会对t.bound进行变异（如果bound不是接口），因此请确保在返回前完成此操作。
	t.iface()
}

func (t *TypeParam) Underlying() Type {
	return t.iface()
}

func (t *TypeParam) String() string { return TypeString(t, nil) }

// ---------------------------------------------------------------
// 实现

func (t *TypeParam) cleanup() {
	t.iface()
	t.check = nil
}

// iface返回t的约束接口。
func (t *TypeParam) iface() *Interface {
	bound := t.bound

	// 确定约束接口
	var ityp *Interface
	switch u := under(bound).(type) {
	case *Basic:
		if u == Typ[Invalid] {
			// 其他地方报告错误
			return &emptyInterface
		}
	case *Interface:
		if isTypeParam(bound) {
			// 检查程序中报告错误。collectTypeParams 
			return &emptyInterface
		}
		ityp = u
	}

	// 如果没有接口，请将约束包装到隐式接口中。
	if ityp == nil {
		ityp = NewInterfaceType(nil, []Type{bound})
		ityp.implicit = true
		t.bound = ityp // 更新t.bound以备下次（优化）
	}

	// 必要时计算类型集
	if ityp.tset == nil {
		// pos用于跟踪输出；从类型参数位置开始。
		pos := t.obj.pos
		// 如果我们有一个
		if n, _ := bound.(*Named); n != nil {
			pos = n.obj.pos
		}
		computeInterfaceTypeSet(t.check, pos, ityp)
	}

	return ityp
}

// 使用t约束的特定类型项调用f，则使用（原始或可能实例化的）类型绑定位置，并报告
// 是否所有对f的调用都返回true。如果没有具体的术语，is 
// 返回f（nil）的结果。
func (t *TypeParam) is(f func(*term) bool) bool {
	return t.iface().typeSet().is(f)
}

// underIs使用t的约束的特定类型项
// 的底层类型调用f，并报告是否所有对f的调用都返回true。
// 如果没有具体的条款，underIs将返回f（nil）的结果。
func (t *TypeParam) underIs(f func(Type) bool) bool {
	return t.iface().typeSet().underIs(f)
}
